package com.itemp.ms66scan;//package xxx

import android.text.TextUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Locale;

/**
 * Byte转换工具
 *
 * @author yangle
 */
public class ByteUtils {
    private final static char[] digits = "0123456789ABCDEF".toCharArray();
    // 判断字符串是否是16进制的
    private final static String hexRegex = "^[A-Fa-f0-9]+$";

    /**
     * byte[]转十六进制字符串
     *
     * @param array byte[]
     * @return 十六进制字符?
     */
    public static String byteArrayToHexString(byte[] array) {
        if (array == null) {
            return "";
        }
        StringBuilder buffer = new StringBuilder();
        for (byte b : array) {
            buffer.append(byteToHex(b));
        }
        return buffer.toString();
    }

    /**
     * byte转十六进制字
     *
     * @param b byte:0-255，无符号
     * @return 十六进制字符, 长度=2
     */
    public static String byteToHex(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        return hex.toUpperCase(Locale.getDefault());
    }

    /**
     * 高效写法 16进制字符串转成byte数组
     *
     * @param hex 16进制字符串，支持大小写
     * @return byte数组
     */
    public static byte[] hexStringToBytes(String hex) {
        if (TextUtils.isEmpty(hex)) {
            return null;
        }
        byte[] result = new byte[hex.length() / 2];
        char[] chars = hex.toCharArray();
        for (int i = 0, j = 0; i < result.length; i++) {
            result[i] = (byte) (toByte(chars[j++]) << 4 | toByte(chars[j++]));
        }
        return result;
    }

    private static int toByte(char c) {
        if (c >= '0' && c <= '9')
            return (c - '0');
        if (c >= 'A' && c <= 'F')
            return (c - 'A' + 0x0A);
        if (c >= 'a' && c <= 'f')
            return (c - 'a' + 0x0a);
        throw new RuntimeException("invalid hex char '" + c + "'");
    }

    /**
     * 高效写法 byte数组转成16进制字符串
     *
     * @param bytes byte数组
     * @return 16进制字符串
     */
    public static String bytesToHexString(byte[] bytes) {
        char[] buf = new char[bytes.length * 2];
        int c = 0;
        for (byte b : bytes) {
            buf[c++] = digits[(b >> 4) & 0x0F];
            buf[c++] = digits[b & 0x0F];
        }
        return new String(buf);
    }

    /**
     * 判断字符串是否是16进制的, 空字符串也返回true
     **/
    public static boolean isHexStringAllowEmpty(String str) {
        if (str != null) {
            if (str.length() > 0) {
                return str.matches(hexRegex);
            } else {
                return true;
            }
        }
        return false;
    }

    // 从byte数组的index处的连续两个字节获得一个short，大端字节数组
    public static short getShortFromBigEndian(byte[] arr, int index) {
        if (arr == null || arr.length <= 0 || index < 0 || (index + 1) >= arr.length) {
            return 0;
        }
        return (short) (0xff00 & arr[index] << 8 | (0xff & arr[index + 1]));
    }

    // 从byte数组的index处的连续两个字节获得一个short，大端字节数组
    public static short getShortFromBigEndian(byte[] arr) {
        if (arr == null || arr.length <= 0) {
            return 0;
        }
        return ByteBuffer.wrap(arr).order(ByteOrder.BIG_ENDIAN).getShort();
    }

    // 小端字节数组转short
    public static short getShortFromLittleEndian(byte[] bytes) {
        if (bytes == null || bytes.length <= 0) {
            return 0;
        }
        return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
    }

    /**
     * int转十六进制字符串
     *
     * @param i 整数
     * @return 十六进制字符，长度为8，大端
     */
    public static String intToHexBig(int i) {
        String hex = Integer.toHexString(i);
        // 补0，补成偶数位
        String hexPrefix = "";
        if (hex.length() % 2 != 0) {
            hexPrefix = "0";
        }
        return (hexPrefix + hex).toUpperCase(Locale.getDefault());
    }

    /**
     * int转十六进制字符串
     *
     * @param i 整数
     * @return 十六进制字符，长度为8，小端
     */
    public static String intToHexLittle(int i) {
        byte[] result = intToByte4Little(i);
        return byteArrayToHexString(result);
    }

    /**
     * byte数组转换为int
     * 大端方式将4字节转整型
     *
     * @param bytes byte数组
     * @param off   开始位置
     * @return int 整数
     */
    public static int byte4ToIntBig(byte[] bytes, int off) {
        if (bytes == null || bytes.length <= 0 || off < 0 || (off + 3) >= bytes.length) {
            return 0;
        }
        int b0 = bytes[off] & 0xFF;
        int b1 = bytes[off + 1] & 0xFF;
        int b2 = bytes[off + 2] & 0xFF;
        int b3 = bytes[off + 3] & 0xFF;
        return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
    }

    /**
     * byte数组转换为int
     * 小端方式将4字节转整型
     *
     * @param bytes byte数组
     * @param off   开始位置
     * @return int 整数
     */
    public static int byte4ToIntLittle(byte[] bytes, int off) {
        if (bytes == null || bytes.length <= 0 || off < 0 || (off + 3) >= bytes.length) {
            return 0;
        }
        int b0 = bytes[off] & 0xFF;
        int b1 = bytes[off + 1] & 0xFF;
        int b2 = bytes[off + 2] & 0xFF;
        int b3 = bytes[off + 3] & 0xFF;
        return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
    }

    /**
     * int整数转换为4字节的byte数组(大端)
     *
     * @param i 整数
     * @return byte数组
     */
    public static byte[] intToByte4Big(int i) {
        byte[] targets = new byte[4];
        targets[3] = (byte) (i & 0xFF);
        targets[2] = (byte) (i >> 8 & 0xFF);
        targets[1] = (byte) (i >> 16 & 0xFF);
        targets[0] = (byte) (i >> 24 & 0xFF);
        return targets;
    }

    /**
     * int整数转换为4字节的byte数组(小端)
     *
     * @param i 整数
     * @return byte数组
     */
    public static byte[] intToByte4Little(int i) {
        byte[] targets = new byte[4];
        targets[0] = (byte) (i & 0xFF);
        targets[1] = (byte) (i >> 8 & 0xFF);
        targets[2] = (byte) (i >> 16 & 0xFF);
        targets[3] = (byte) (i >> 24 & 0xFF);
        return targets;
    }

    private static String toHexUtil(int n) {
        String rt = "";
        switch (n) {
            case 10:
                rt += "A";
                break;
            case 11:
                rt += "B";
                break;
            case 12:
                rt += "C";
                break;
            case 13:
                rt += "D";
                break;
            case 14:
                rt += "E";
                break;
            case 15:
                rt += "F";
                break;
            default:
                rt += n;
        }
        return rt;
    }

    private static String toHex(int n) {
        StringBuilder sb = new StringBuilder();
        if (n / 16 == 0) {
            return toHexUtil(n);
        } else {
            String t = toHex(n / 16);
            int nn = n % 16;
            sb.append(t).append(toHexUtil(nn));
        }
        return sb.toString();
    }

    /**
     * ascii码(字符串，仅限英文字符)转16进制字符串
     **/
    public static String asciiStrToHexStr(String str) {
        StringBuilder sb = new StringBuilder();
        byte[] bs = str.getBytes();
        for (int i = 0; i < bs.length; i++)
            sb.append(toHex(bs[i]));
        return sb.toString();
    }

    /**
     * 16进制字符串转ascii字符串
     **/
    public static String hexStrToAsciiStr(String hex) {
        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();
        // 49204c6f7665204a617661 split into two characters 49, 20, 4c...
        for (int i = 0; i < hex.length() - 1; i += 2) {
            // grab the hex in pairs
            String output = hex.substring(i, (i + 2));
            // convert hex to decimal
            int decimal = Integer.parseInt(output, 16);
            // convert the decimal to character
            sb.append((char) decimal);
            temp.append(decimal);
        }
        return sb.toString();
    }

    /**
     * ascii字符串转字节数组 ascii to bytes
     **/
    public static byte[] asciiToBytes(String ascii) {
        char[] ch = ascii.toCharArray();
        byte[] tmp = new byte[ch.length];
        for (int i = 0; i < ch.length; i++) {
            tmp[i] = (byte) Integer.valueOf(ch[i]).intValue();
        }
        return tmp;
    }

    /**
     * bytes to ascii
     **/
    public static String bytesToAscii(byte[] bytes) {
        String s = "";
        try {
            s = new String(bytes, "ascii");
        } catch (UnsupportedEncodingException e) {
            System.out.println("bytesToAscii error=" + e.getMessage() + ", bytes=" + bytes);
            e.printStackTrace();
        }
        return s;
    }

    /**
     * 是否是合法的ascii码
     **/
    public static boolean isValidAsciiString(String string) {
        try {
            String hex = asciiStrToHexStr(string);
            ByteUtils.hexStringToBytes(hex);
            return true;
        } catch (Exception e) {
            System.out.println("isValidAsciiString error=" + e.getMessage() + ", string=" + string);
            e.printStackTrace();
        }
        return false;
    }

    // byte 与 int 的相互转换
    public static byte intToByte(int x) {
        return (byte) x;
    }

    // byte 与 int 的相互转换 ， byte转无符号整型
    public static int byteToInt(byte b) {
        // Java 总是把 byte 当做有符处理；我们可以通过将其和 0xFF 进行二进制与得到它的无符值
        return b & 0xFF;
    }

    public static byte[] unsignedShortToByte2(int s) {
        byte[] targets = new byte[2];
        targets[0] = (byte) (s >> 8 & 0xFF);
        targets[1] = (byte) (s & 0xFF);
        return targets;
    }

    /**
     * 大端、小端方式, short值转2字节数据
     **/
    public static void putShort(byte b[], short s, boolean isBigEdian) {
        if (b == null || b.length <= 0 || b.length > 2) {
            return;
        }
        if (!isBigEdian) {
            b[1] = (byte) (s >> 8);
            b[0] = (byte) (s >> 0);
        } else {
            b[1] = (byte) (s >> 0);
            b[0] = (byte) (s >> 8);
        }
    }

    /**
     * 大端、小端方式，两字节数据转short值
     * 大端序：高位字节在前，低位字节在后。
     * 小端序：低位字节在前，高位字节在后。
     **/
    public static short getShort(byte[] b, boolean isBigEndian) {
        if (b == null || b.length <= 0 || b.length > 2) {
            return 0;
        }
        if (!isBigEndian) {
            return (short) (((b[1] << 8) | b[0] & 0xff));
        } else {
            return (short) (((b[1] & 0xff) | b[0] << 8));
        }
    }

    /**
     * short类型转成两个字节(大端)的16进制字符串，长度=4
     **/
    public static String shortToHexBig(short s) {
        if (s < Short.MIN_VALUE || s > Short.MAX_VALUE) {
            return "0000";
        }
        String result = Integer.toHexString(s & 0xffff);
        // 不足4位补0
        String prefix = "";
        // short类型的数据，使用16进制表示时的长度
        int shortHexLen = Short.BYTES * 2;
        if (result.length() < shortHexLen) {
            for (int i = 0; i < shortHexLen - result.length(); i++) {
                prefix += "0";
            }
        }
        return prefix + result;
    }

    /**
     * short类型转成两个字节(小端)的16进制字符串，长度=4
     **/
    public static String shortToHexLittle(short s) {
        if (s < Short.MIN_VALUE || s > Short.MAX_VALUE) {
            return "0000";
        }
        byte[] bytes = new byte[2];
        putShort(bytes, s, false);
        return byteArrayToHexString(bytes);
    }

    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }

    /**
     * 拼接两个字节数组
     **/
    public static byte[] concatByteArray(byte[] bytes1, byte[] bytes2) {
        if (bytes1 == null || bytes1.length <= 0 || bytes2 == null || bytes2.length <= 0)
            return null;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            outputStream.write(bytes1);
            outputStream.write(bytes2);
            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * long类型转byte[] (大端)
     * @param n 长整型
     * @return 8字节数组
     */
    public static byte[] longToBytesBig(long n) {
        byte[] b = new byte[8];
        b[7] = (byte) (n & 0xff);
        b[6] = (byte) (n >> 8  & 0xff);
        b[5] = (byte) (n >> 16 & 0xff);
        b[4] = (byte) (n >> 24 & 0xff);
        b[3] = (byte) (n >> 32 & 0xff);
        b[2] = (byte) (n >> 40 & 0xff);
        b[1] = (byte) (n >> 48 & 0xff);
        b[0] = (byte) (n >> 56 & 0xff);
        return b;
    }

    /**
     * long类型转byte[] (小端)
     *
     * @param n 长整型
     * @return 8字节数组
     */
    public static byte[] longToBytesLittle(long n) {
        byte[] b = new byte[8];
        b[0] = (byte) (n & 0xff);
        b[1] = (byte) (n >> 8 & 0xff);
        b[2] = (byte) (n >> 16 & 0xff);
        b[3] = (byte) (n >> 24 & 0xff);
        b[4] = (byte) (n >> 32 & 0xff);
        b[5] = (byte) (n >> 40 & 0xff);
        b[6] = (byte) (n >> 48 & 0xff);
        b[7] = (byte) (n >> 56 & 0xff);
        return b;
    }

    /**
     * byte[]转long类型(小端)
     * @param array 8字节数组
     * @return 长整型
     */
    public static long bytesToLongLittle(byte[] array) {
        if (array == null || array.length < 8)
            return 0;
        return ((((long) array[0] & 0xff) << 0)
                | (((long) array[1] & 0xff) << 8)
                | (((long) array[2] & 0xff) << 16)
                | (((long) array[3] & 0xff) << 24)
                | (((long) array[4] & 0xff) << 32)
                | (((long) array[5] & 0xff) << 40)
                | (((long) array[6] & 0xff) << 48)
                | (((long) array[7] & 0xff) << 56));
    }

    /**
     * byte[]转long类型(大端)
     * @param array 8字节数组
     * @return 长整型
     */
    public static long bytesToLongBig(byte[] array) {
        if (array == null || array.length < 8)
            return 0;
        return ((((long) array[0] & 0xff) << 56)
                | (((long) array[1] & 0xff) << 48)
                | (((long) array[2] & 0xff) << 40)
                | (((long) array[3] & 0xff) << 32)
                | (((long) array[4] & 0xff) << 24)
                | (((long) array[5] & 0xff) << 16)
                | (((long) array[6] & 0xff) << 8)
                | (((long) array[7] & 0xff) << 0));
    }
}